﻿using System;
using System.IO;
using System.Net;
using Mono.Options;

using octalforty.Componento.Core.ApplicationServices;
using octalforty.Componento.Core.ObjectModel;
using octalforty.Componento.Impl;
using octalforty.Componento.Core.Util;

using System.Linq;

namespace octalforty.Componento.Commands
{
    [Command("install", Aliases = "i")]
    public class InstallCommand : ICommand
    {
        public class Options
        {
            public bool Local
            { get; set; }

            public bool Latest
            { get; set; }

            public string RepositoryAlias
            { get; set; }

            public bool Probe
            { get; set; }

            public string Proxy
            { get; set; }
        }

        public MetadirectoryManagerService MetadirectoryManager
        { get; set; }

        public PackageRepositoryBrowserService PackageRepositoryBrowser
        { get; set; }

        public DependencyGraphManagerService DependencyGraphManager
        { get; set; }

        public PackageInstallerService PackageInstaller
        { get; set; }

        public OptionSet GetOptionSet(object options)
        {
            throw new NotImplementedException();
        }

        public void Execute(string[] args)
        {
            var options = new Options { Local = false, RepositoryAlias = "default", Probe = true, Latest = true };
            var optionSet = new OptionSet {
                { "p|probe", "Specifies whether to probe directories for \"lib\". Default is \"true\".", p => options.Probe = p != null },
                { "l|local", "", l => options.Local = l != null },
                { "r:|repository:", "", r => options.RepositoryAlias = r },
                { "la|latest", "Installs latest package version. Default is \"true\".", la => options.Latest = la != null },
                { "proxy:", "", proxy => options.Proxy = proxy }
            };

            var rest = optionSet.Parse(args);
            
            if(!options.Proxy.IsNullOrEmpty())
                WebRequest.DefaultWebProxy =
                    new WebProxy(options.Proxy.SubstringBefore(":"), int.Parse(options.Proxy.SubstringAfter(":")));
            
            var repositoryUri = MetadirectoryManager.GetRepositoryUri(Directory.GetCurrentDirectory(), options.Probe, options.RepositoryAlias);

            if(args.Length == 0)
            {
                
            }
            else
            {
                PackageInstaller.InstallingPackage += (sender, eventArgs) => {
                    Console.Out.WriteLine(ConsoleColor.Yellow, "  Installing {0} {1}", eventArgs.Manifest.Name, eventArgs.Manifest.Version);
                };

                PackageInstaller.InstallingResource += (sender, eventArgs) => {
                    Console.Out.WriteLine(ConsoleColor.Gray, "    Installing {0} to '{1}'", eventArgs.Resource.GetLastSegment(), eventArgs.TargetDirectory);
                };

                var libPath = MetadirectoryManager.GetProbedPath(options.Probe, Directory.GetCurrentDirectory());
                Console.Out.WriteLine("Installing packages to '{0}'", libPath);

                foreach(var packageName in rest)
                {
                    Console.Out.WriteLine(ConsoleColor.Gray, "Listing package manifests for {0}", packageName);
                    var packages = PackageRepositoryBrowser.GetPackageManifests(repositoryUri, packageName, null).ToList();

                    Console.Out.WriteLine(ConsoleColor.Gray, "Found {0} packages", packages.Count);

                    var package = packages.OrderByDescending(p => p.Version).First();
                    PackageInstaller.Install(libPath, package, repositoryUri);
                }
            } // else
        }
    }
}
